package com.template.mongo.persistence.dao.base;

import java.lang.reflect.ParameterizedType;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.template.mongo.model.BaseBean;
import com.template.mongo.utils.PagingInfo;

public class GenericMongoBaseDaoImpl<T extends BaseBean> implements GenericMongoBaseDao<T>{
	
	private final Class<T> persistentClass;
	protected String singleClassName = "";

    @SuppressWarnings("unchecked")
	public GenericMongoBaseDaoImpl() {
            this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
    				.getGenericSuperclass()).getActualTypeArguments()[0];
    		singleClassName = persistentClass.getSimpleName();
    }

    public GenericMongoBaseDaoImpl(final Class<T> persistentClass) {
		this.persistentClass = persistentClass;
		singleClassName = persistentClass.getSimpleName();
	}

    @Override
	public Class<T> getEntityClass() {
		return persistentClass;
	}

	@Autowired
    protected MongoTemplate mongoTemplate;

    public MongoTemplate getMongoTemplate() {
            return mongoTemplate;
    }

    @Override
    public void save(T bean) {
            mongoTemplate.insert(bean);
    }
    
    @Override
    public void update(T bean) {
            Query query = new Query(Criteria.where(bean.getKeyName()).is(
                            bean.getKeyValue()));
            Update update = new Update();

            Map<String, Object> map = bean.toMap();

            Iterator<String> iterator = map.keySet().iterator();

            while (iterator.hasNext()) {
                    String key = iterator.next();
                    update.set(key, map.get(key));
            }

            mongoTemplate.updateFirst(query, update, persistentClass);
    }

    @Override
    public void delete(T bean) {
            mongoTemplate.remove(bean);
    }

    @Override
	public T findById(ObjectId id) {
		return mongoTemplate.findById(id, persistentClass);
	}

	@Override
	public T findOne(Map<String, Object> map) {
		Query query = new Query();
		Iterator<String> iterator = map.keySet().iterator();

		while (iterator.hasNext()) {
			String key = iterator.next();
			if (map.get(key) != null) {
				query.addCriteria(Criteria.where(key).is(map.get(key)));
			}
		}
		return mongoTemplate.findOne(query, persistentClass);
	}
	
	@Override
	public T findOne(T bean) {
		Map<String, Object> map = bean.toMap();
		return findOne(map);
	}
	
	@Override
	public T findOne(Query query) {
		return mongoTemplate.findOne(query, persistentClass);
	}
	
	/**
	 * Count entity
	 * @return number of all items according to condition
	 */
	@Override
	public Long count(Query query) {
		return mongoTemplate.count(query, persistentClass);
	}

	@Override
	public List<T> findAll() {
		return mongoTemplate.findAll(persistentClass);
	}

	@Override
	public List<T> findAll(PagingInfo pInfo) {
		return null;
	}

	

}